package org.pupil.spi;


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicReference;

/**
 * @Description: 扩展加载器，SPI机制，动态地为接口寻找服务实现
 * @Author: pupil
 * @Date: 2024/07/19 下午 3:34
 */
public class ExtensionLoader {

    // 系统SPI 前缀
    private static String SYS_EXTENSION_LOADER_DIR_PREFIX = "META-INF/prpc/";

    // 用户SPI 前缀
    private static String DIY_EXTENSION_LOADER_DIR_PREFIX = "META-INF/rpc/";

    // 前缀集合
    private static String[] prefixes = {SYS_EXTENSION_LOADER_DIR_PREFIX, DIY_EXTENSION_LOADER_DIR_PREFIX};

    // bean定义信息 key: 定义的key value：具体类
    private static Map<String, Class> extensionClassCache = new ConcurrentHashMap<>();
    // bean 定义信息 key：接口 value：接口子类的集合
    private static Map<String, Map<String, Class>> extensionClassCaches = new ConcurrentHashMap<>();

    // 实例化的bean
    private static Map<String, Object> singletonsObject = new ConcurrentHashMap<>();

    // 实现单例模式的SPI（cas实现线程安全）
    private static final AtomicReference<ExtensionLoader> INSTANCE = new AtomicReference<>();
    private static ExtensionLoader extensionLoader;

    public ExtensionLoader() {
    }

    /*static {
        extensionLoader = new ExtensionLoader();
    }*/

    // 获取SPI
   /* public static ExtensionLoader getInstance(){
        return extensionLoader;
    }*/

    // 获取SPI
    public static final ExtensionLoader getInstance() {
        for (; ; ) {
            ExtensionLoader extensionLoader = INSTANCE.get();
            if (null != extensionLoader) return extensionLoader;
            INSTANCE.compareAndSet(null, new ExtensionLoader());
            return INSTANCE.get();
        }
    }

    /**
     * 根据spi机制初加载bean的信息放入map
     *
     * @param clazz
     * @throws IOException
     * @throws ClassNotFoundException
     */
    public void loadExtension(Class clazz) throws IOException, ClassNotFoundException {
        if (clazz == null) {
            throw new IllegalArgumentException("class 没找到");
        }
        // 获取类加载器
        ClassLoader classLoader = this.getClass().getClassLoader();
        // 存储接口子类的集合
        Map<String, Class> classMap = new HashMap<>();
        // 从系统SPI以及用户SPI中找bean
        for (String prefix : prefixes) {
            // SPI接口配置文件路径
            String spiFilePath = prefix + clazz.getName();
            // 根据SPI接口配置文件路径读取资源
            Enumeration<URL> resources = classLoader.getResources(spiFilePath);
            // 循环读取配置文件的内容
            while (resources.hasMoreElements()) {
                // 获取url资源
                URL url = resources.nextElement();
                // 将url资源转换成字节流
                InputStreamReader inputStreamReader = new InputStreamReader(url.openStream());
                // 从字节流中读取数据到缓冲区中
                BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
                // 读取整行内容
                String line;
                while ((line = bufferedReader.readLine()) != null) {
                    // 根据 = 进行字符串分割
                    String[] lineArr = line.split("=");
                    // 名字
                    String key = lineArr[0];
                    // 类名
                    String name = lineArr[1];
                    // 通过类名获取类的class
                    Class<?> aClass = Class.forName(name);
                    // 存储在缓存中
                    extensionClassCache.put(key, aClass);
                    // 存储在接口子类的集合
                    classMap.put(key, aClass);
                }
            }
        }
        // 存在缓存中
        extensionClassCaches.put(clazz.getName(), classMap);
    }


    /**
     * 获取类（实例化的bean）
     *
     * @param name
     * @param <V>
     * @return
     */
    public <V> V get(String name) {
        // 判断是否存在该bean
        if (!singletonsObject.containsKey(name)) {
            // 不存在，则进行实例化并存储在singletonsObject缓存中
            try {
                singletonsObject.put(name, extensionClassCache.get(name).newInstance());
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
        return (V) singletonsObject.get(name);
    }


    /**
     * 获取接口下所有的类（实例化的bean）
     *
     * @param clazz
     * @return
     */
    public List gets(Class clazz) {
        // 类名
        String name = clazz.getName();
        if (!extensionClassCaches.containsKey(name)) {
            try {
                throw new ClassNotFoundException(clazz + "未找到");
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
        // 获取接口下所有类集合
        final Map<String, Class> stringClassMap = extensionClassCaches.get(name);
        // 存储接口下所有的类
        List<Object> objects = new ArrayList<>();
        if (stringClassMap.size() > 0) {
            stringClassMap.forEach((k, v) -> {
                try {
                    objects.add(singletonsObject.getOrDefault(k, v.newInstance()));
                } catch (InstantiationException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            });
        }
        return objects;
    }

}
